﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using CucumberJwt.Application.Authorization.Audit.Service;
using CucumberJwt.Application.Authorization.Jwt.Dto;
using CucumberJwt.Application.Authorization.Jwt.IService;
using CucumberJwt.Application.Authorization.Jwt.Service;
using EntityFrameworkCore;
using FrameworkCore.Dependency;
using FrameworkCore.Dependency.AutoMapper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Cors.Internal;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.IdentityModel.Tokens;
using Swashbuckle.AspNetCore.Swagger;
using Wangkanai.Detection;
using WebApi.Filter;

namespace WebApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }
        private const string ApiName = "CucumberJwt";
        private const string _defaultCorsPolicyName = "CucumberJwt1";
        private  Assembly assembly = Assembly.Load("WebApi");
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            JwtSettings setting = new JwtSettings();
            SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.SecretKey));

            services.AddTransient<IJwtAppService, JwtAppService>();
            var basePath = PlatformServices.Default.Application.ApplicationBasePath;

            #region 注释
            //services.AddSwaggerGen(options =>
            //{
            //    options.SwaggerDoc("v1", new Info
            //    {
            //        Version = "v1",
            //        Title = "MsSystem API"
            //    });

            //    //Determine base path for the application.  

            //    //Set the comments path for the swagger json and ui.  
            //    var xmlPath = Path.Combine(basePath, "WebApi.xml");

            //    options.IncludeXmlComments(xmlPath);
            //    options.IncludeXmlComments(Path.Combine(basePath, "CucumberJwt.Application.xml"));
            //});

            #endregion

            #region 参数
            var tokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
            {

                ValidateIssuerSigningKey = true,
                IssuerSigningKey = key,
                ValidateIssuer = true,
                ValidIssuer = setting.Issuer,//发行人
                ValidateAudience = true,
                ValidAudience = setting.Audience,//订阅人
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero,
                RequireExpirationTime = true,
            };
            #endregion
            //1【授权】、自定义复杂授权的权限要求
            services.AddAuthorization(options =>
            {
                options.AddPolicy("Permission",
                         policy => policy.Requirements.Add(new PermissionRequirement()));
            });
            services.AddAuthentication(options =>
            {
                //认证middleware配置
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(o =>
            {
                o.TokenValidationParameters = tokenValidationParameters;
                o.Events = new JwtBearerEvents()
                {
                    OnAuthenticationFailed= context => {
                        // 如果过期，则把<是否过期>添加到，返回头信息中
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                        }
                        return Task.CompletedTask;
                    }

                };

            });


            #region
            services.AddSingleton<IAuthorizationHandler, PermissionHandler>();

            services.AddScoped<IUnitOfWork, UnitOfWork>();

            services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
            services.AddTransient<IAuditService, AuditService>();
            services.AddDetectionCore().AddBrowser();
            #endregion


            #region mvc

            services.AddMvc(options => {
                options.Filters.Add(new AuditActionFilter());
              options.Filters.Add(new CorsAuthorizationFilterFactory(_defaultCorsPolicyName));
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2)            
            // 取消默认驼峰
            .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver(); });;
            services.AddSingleton(typeof(IHttpContextAccessor),typeof(HttpContextAccessor));
            #endregion



            #region cors
            services.AddCors(options => options.AddPolicy(_defaultCorsPolicyName,
          builder => builder.WithOrigins(
                  Configuration["Application:CorsOrigins"]
                  .Split(",", StringSplitOptions.RemoveEmptyEntries).ToArray()
              )
          .AllowAnyHeader()
          .AllowAnyMethod()
          .AllowCredentials()));
            #endregion
            #region Swagger
            services.AddSwaggerGen(c =>
            {

                assembly.GetTypes().Where(o => o.GetCustomAttribute<CustomRouteAttribute>() != null).Select(o => o.GetCustomAttribute<CustomRouteAttribute>()).ToList().ForEach(version => {

                    c.SwaggerDoc(version.GroupName, new Info
                    {
                        // {ApiName} 定义成全局变量，方便修改
                        Version = version.GroupName,
                        Title = $"大黄瓜接口文档",
                        Description = $"大黄瓜 HTTP API " + version.GroupName,
                        TermsOfService = "None",
                        Contact = new Contact { Name = "大黄瓜", Email = "179722134@qq.com", Url = "" }
                    });
                    // 按相对路径排序
                    c.OrderActionsBy(o => o.RelativePath);
                });





                var xmlPath = Path.Combine(basePath, "WebApi.xml");

                c.IncludeXmlComments(xmlPath, true);
                c.IncludeXmlComments(Path.Combine(basePath, "CucumberJwt.Application.xml"), true);

                c.AddSecurityDefinition("Bearer", new ApiKeyScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}（注意两者之间是一个空格）\"",
                    Name = "Authorization",//jwt默认的参数名称
                    In = "header",//jwt默认存放Authorization信息的位置(请求头中)
                    Type = "apiKey"
                });

                c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
                {
                    { "Bearer", new string[] { } }
                });
            });
            #endregion



            services.AddDbContext<AuditDbContext>();


            #region automapper

            //var attributes = { AutoMapFromAttribute, AutoMapAttribute, AutoMapToAttribute };
            RuntimeHelper.GetAllTypes()
                .Where(o=>
                   o.GetCustomAttribute<AutoMapAttribute>()!=null
                || o.GetCustomAttribute<AutoMapAttribute>() != null 
                || o.GetCustomAttribute<AutoMapToAttribute>() != null
                )
                .ToList()
                .ForEach(type => {
                AutoMapperHelper.CreateMap(type);
            });

            AutoMapperHelper.Register();  //创建映射完毕后进行注
            #endregion


            var serviceProvider = services.BuildServiceProvider();
            ServiceLocator.Instance.SetApplicationServiceProvider(serviceProvider);

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }



            app.UseCors(_defaultCorsPolicyName);
          
            app.UseAuthentication();

            app.UseMvc();


            //app.UseSwagger(o =>
            //{
            //    o.PreSerializeFilters.Add((document, request) =>
            //    {
            //        document.Paths = document.Paths.ToDictionary(p => p.Key.ToLowerInvariant(), p => p.Value);
            //    });
            //});

            app.UseSwagger();
            app.UseSwaggerUI(c => {

                assembly.GetTypes().Where(o => o.GetCustomAttribute<CustomRouteAttribute>() != null).Select(o => o.GetCustomAttribute<CustomRouteAttribute>()).ToList().ForEach(v =>
                {

                    c.SwaggerEndpoint($"/swagger/{v.GroupName}/swagger.json", $"大黄瓜 {v.GroupName}");
                });
                c.IndexStream = () => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("WebApi.index.html");
                c.RoutePrefix = ""; //路径配置，设置为空，表示直接在根域名（localhost:8001）访问该文件,注意localhost:8001/swagger是访问不到的，去launchSettings.json把launchUrl去掉
            });



        }
    }
}
